import config from '@/config';
import { ApplicationModel, IApplication } from '@/models/application';
import { pathIsOk } from '@/utils/tools';
import fs from 'fs/promises';
import path from 'path';
import { Socket } from 'socket.io';
import { z } from 'zod';

import EmitTask from '../utils/emitTask';
import runCommand from '../utils/runCommand';

const addApplicationSchema = z.object({
  branch: z
    .string({
      invalid_type_error: 'Git仓库分支必须是字符串',
      required_error: 'Git仓库分支不能为空',
    })
    .min(1, 'Git仓库分支不能为空'),
  git: z
    .string({
      invalid_type_error: 'Git仓库地址必须是字符串',
      required_error: 'Git仓库地址不能为空',
    })
    .min(1, 'Git仓库地址不能为空')
    .regex(
      /^(?:https?:\/\/|git@)[\w.-]+[/:]([\w.-]+\/[\w.-]+)(?:\.git)?$/,
      'Git仓库地址格式无效，请提供有效的Git仓库URL',
    ),
  remark: z
    .string()
    .max(500, '描述不能超过500个字符')
    .transform(val => val?.trim())
    .default(''),
  type: z.enum(['base', 'pure-pages'], {
    invalid_type_error: '应用类型无效',
    required_error: '应用类型不能为空',
  }),
});

/**
 * 添加应用并克隆代码
 *
 * @param socket - Socket实例
 * @param data - 包含应用信息的数据对象
 * @returns Promise<void>
 */
export default async function (socket: Socket, data: unknown): Promise<void> {
  const emitTask = new EmitTask(socket, 'add-application');
  emitTask.start();

  try {
    // 验证输入数据
    const validatedData = addApplicationSchema.parse(data);
    const { branch, git, remark, type } = validatedData;

    // 提取应用名（去除.git后缀，兼容多种格式）
    const repoPath = git.split('/').pop() || '';
    const repoName = repoPath.replace(/\.git$/, '');
    const name = `${repoName}-${branch}`;
    emitTask.info(`开始添加应用 ${name}`);

    // 检查应用是否已存在
    const existingRepo = await ApplicationModel.findOne({ name });
    if (existingRepo) {
      return emitTask.errorEnd('应用已存在');
    }

    // 构建应用数据
    const repoData: IApplication = { branch, git, name, remark, type };

    // 保存应用数据到数据库
    let savedRepo;
    try {
      const repo = new ApplicationModel(repoData);
      savedRepo = await repo.save();
      emitTask.info('应用信息保存成功');
    } catch (dbError) {
      return emitTask.errorEnd(`保存应用信息失败: ${String(dbError)}`);
    }

    // 创建应用目录
    const repoDir = path.join(config.repoPath, savedRepo._id.toString());
    try {
      const mk = await fs.mkdir(repoDir, { recursive: true });
      console.log('mk', mk);
    } catch (fsError) {
      // 如果创建目录失败，回滚数据库操作
      await ApplicationModel.deleteOne({ _id: savedRepo._id });
      return emitTask.errorEnd(`创建应用目录失败: ${String(fsError)}`);
    }
    emitTask.info(`创建应用目录成功: ${repoDir}`);

    // 克隆应用
    try {
      emitTask.info(`开始克隆应用: ${git} 分支: ${branch}`);
      await runCommand(emitTask, 'git', ['clone', git, '-b', branch, '.'], {
        cwd: repoDir,
        shell: true,
      });
      emitTask.info('应用克隆成功');

      // 验证克隆是否成功
      const cloneSuccess = await pathIsOk(repoDir);
      if (!cloneSuccess) {
        throw new Error('应用克隆成功但目录不存在');
      }

      return emitTask.successEnd('应用添加成功');
    } catch (gitError) {
      // 如果克隆失败，回滚数据库操作和文件系统操作
      await ApplicationModel.deleteOne({ _id: savedRepo._id });
      try {
        await fs.rm(repoDir, { force: true, recursive: true });
      } catch (cleanupError) {
        emitTask.error(`清理应用目录失败: ${String(cleanupError)}`);
      }
      return emitTask.errorEnd(`克隆应用失败: ${String(gitError)}`);
    }
  } catch (err) {
    if (err instanceof z.ZodError) {
      // 处理验证错误
      return emitTask.errorEnd(`数据验证失败: ${err.errors.map(e => e.message).join(', ')}`);
    }
    return emitTask.errorEnd(`处理出错: ${String(err)}`);
  }
}
